/**
 * 
 */
package com.zaprit.search.support;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.FieldStatsInfo;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;

import com.rdo.util.search.FacetedSearchCriteria;
import com.rdo.util.search.FacetedSearchResult;
import com.rdo.util.search.SearchCondition;
import com.zaprit.search.bo.Item;
import com.zaprit.search.exception.SearchException;

/**
 * @author Root
 */
public class SolrSearcher implements ZapritSearcher
{
	private SolrSupport	solrSupport	= null;

	public void setProperties(Properties properties) throws SearchException
	{
		solrSupport = new SolrSupport(properties);
	}

	/**
	 * @param scopeId
	 * @param userId
	 * @param facetedSearchCriteria
	 * @return list of search Items
	 */
	@SuppressWarnings("unchecked")
	public FacetedSearchResult<List<Item>> searchItems(String scopeId, String userId, FacetedSearchCriteria<String> facetedSearchCriteria)
			throws SearchException
	{
		FacetedSearchResult<List<Item>> facetedSearchResult = new FacetedSearchResult<>();
		SolrServer solrServer = solrSupport.getSolrServer(scopeId);
		SolrQuery solrQuery = new SolrQuery();
		List<Item> itemList = new ArrayList<Item>();

		String columnName = null;
		StringBuilder queryBuilder = new StringBuilder();
		try
		{
			for (SearchCondition<String> searchCondition : facetedSearchCriteria.getConditions())
			{
				String column = searchCondition.getColumn();
				columnName = column.substring(9);
				if (column.contains("SEARCH_BY_"))
				{
					queryBuilder.append("(" + columnName + ":" + ClientUtils.escapeQueryChars(searchCondition
							.getStringValue()) + ") &&");
				}
				else if (column.contains("SEARCH_IN_"))
				{
					queryBuilder.append("(" + escape(columnName, searchCondition.getSetValue()) + ") && ");
				}
			}

			// add facet fields
			for (String facet : facetedSearchCriteria.getFacets())
			{
				solrQuery.addFacetField(facet);
			}
			solrQuery.setStart(facetedSearchCriteria.getStartIndex());
			solrQuery.setRows(facetedSearchCriteria.getNoOfRecords());
			QueryResponse queryResponse = solrServer.query(solrQuery);

			SolrDocumentList solrDocumentList = queryResponse.getResults();

			if (solrDocumentList.size() > 0)
			{
				Map<String, FieldStatsInfo> statFields = queryResponse.getFieldStatsInfo();

				if (statFields != null)
				{
					for (Entry<String, FieldStatsInfo> statEntry : statFields.entrySet())
					{
						String fieldName = statEntry.getKey().replace("FCT_", "").replace("FCTD_", "");
						FieldStatsInfo fieldStatsInfo = statEntry.getValue();
						facetedSearchResult.addStatResult(fieldName, "MIN", Double.parseDouble(fieldStatsInfo.getMin()
								.toString()));
						facetedSearchResult.addStatResult(fieldName, "MAX", Double.parseDouble(fieldStatsInfo.getMax()
								.toString()));
					}
				}

				List<FacetField> facetFields = queryResponse.getFacetFields();
				if (facetFields != null)
				{
					for (FacetField facetField : facetFields)
					{
						String fieldName = facetField.getName().replace("FCT_", "").replace("FCTD_", "");
						for (Count count : facetField.getValues())
						{
							facetedSearchResult.addFacetResult(fieldName, count.getName(), count.getCount());
						}
					}
				}
			}

			if (solrDocumentList.size() > 0)
			{
				for (SolrDocument solrDocument : solrDocumentList)
				{
					itemList.add(prepareItem(solrDocument));
				}
			}
		}
		catch (NumberFormatException e)
		{
			throw new SearchException(e);
		}
		catch (SolrServerException e)
		{
			throw new SearchException(e);
		}
		return facetedSearchResult;
	}

	private Item prepareItem(SolrDocument solrDocument)
	{
		return null;
	}

	private String escape(String term)
	{
		// + - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
		term = term.replace("\\", "\\\\");
		term = term.replace("+", "\\+");
		term = term.replace("-", "\\-");
		term = term.replace("&&", "\\&&");
		term = term.replace("||", "\\||");
		term = term.replace("!", "\\!");
		term = term.replace("(", "\\(");
		term = term.replace(")", "\\)");
		term = term.replace("{", "\\{");
		term = term.replace("}", "\\}");
		term = term.replace("[", "\\[");
		term = term.replace("]", "\\]");
		term = term.replace("^", "\\^");
		term = term.replace("\"", "\\\"");
		term = term.replace("~", "\\~");
		term = term.replace("*", "\\*");
		term = term.replace("?", "\\?");
		return term.replace(":", "\\:");
	}

	private String escape(String key, Set<String> terms)
	{
		StringBuffer termString = new StringBuffer();
		for (Iterator<String> iterator = terms.iterator(); iterator.hasNext();)
		{
			termString.append(" (" + key + ":\"" + escape(iterator.next()) + "\")");
			if (iterator.hasNext())
			{
				termString.append(" || ");
			}
		}
		return termString.toString();
	}
}